package com.star.eastern.blee.utils

import android.Manifest
import android.annotation.SuppressLint
import android.app.Dialog
import android.bluetooth.*
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanFilter
import android.bluetooth.le.ScanResult
import android.bluetooth.le.ScanSettings
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.os.ParcelUuid
import android.support.v4.app.FragmentActivity
import android.util.Log
import com.star.eastern.blee.MainActivity
import com.star.eastern.blee.R
import com.tangula.android.utils.ApplicationUtils
import com.tangula.android.utils.PermissionUtils
import com.tangula.android.utils.TaskUtils
import com.tangula.android.utils.ToastUtils
import org.apache.commons.lang3.StringUtils
import java.util.*


internal var HEX_MODE = false

internal var UUID_INPUT = UUID.fromString(UUIDS.INPUT_UUID)!!

internal var UUID_OUTPUT = UUID.fromString(UUIDS.OUTPUT_UUID)!!


internal var LIST_ALL_DEVICE = true

enum class CommandAnswerType {
    NONE, ACK, RESP
}


enum class CommandEnum {
    S1, S2, S3, S4,
    ASW0, ASW1,
    CE0, CE1,
    IR0, IR1,
    L1, L2, L3, L4, L5, L6, L7, L8, L9, L10,
    R1, R2, R3, R4, R5, R6, R7, R8, R9, R10,
    GM, DN, STAT;

    fun answerType(): CommandAnswerType {
        return when (this) {
            S1, S2, S3, S4,
            ASW0, ASW1,
            CE0, CE1,
            IR0, IR1,
            L1, L2, L3, L4, L5, L6, L7, L8, L9, L10, GM, DN -> {
                CommandAnswerType.ACK
            }
            R1, R2, R3, R4, R5, R6, R7, R8, R9, R10 -> {
                CommandAnswerType.NONE
            }
            else -> {
                CommandAnswerType.RESP
            }
        }
    }

}

enum class AckEnum {
    S1A, S2A, S3A, S4A,
    ASW0A, ASW1A,
    CE0A, CE1A,
    IR0A, IR1A,
    L1A, L2A, L3A, L4A, L5A, L6A, L7A, L8A, L9A, L10A,
    GMA, DNA
}

enum class ResponseEnum {
    STAT
}


@SuppressLint("StaticFieldLeak")
lateinit var activity: MainActivity

@Suppress("ConstantConditionIf")
class Tripple7BluetoothCommandProtocol {
    companion object {

        const val SERVICE_UUID = UUIDS.SERVICE_UUID
        const val OUTPUT_UUID = UUIDS.OUTPUT_UUID
        const val INPUT_UUID = UUIDS.INPUT_UUID

        val UUID_SERVICE = UUID.fromString(SERVICE_UUID)!!


        var dialog: Dialog? = null

        private val CMD_TEXT_ENUM_MAP = mapOf<String, CommandEnum>(
            "S1" to CommandEnum.S1,
            "S2" to CommandEnum.S2,
            "S3" to CommandEnum.S3,
            "S4" to CommandEnum.S4,
            "ASW1" to CommandEnum.ASW1,
            "ASW0" to CommandEnum.ASW0,
            "CE1" to CommandEnum.CE1,
            "CE0" to CommandEnum.CE0,
            "IR1" to CommandEnum.IR1,
            "IR0" to CommandEnum.IR0,
            "L10" to CommandEnum.L10,
            "L1" to CommandEnum.L1,
            "L2" to CommandEnum.L2,
            "L3" to CommandEnum.L3,
            "L4" to CommandEnum.L4,
            "L5" to CommandEnum.L5,
            "L6" to CommandEnum.L6,
            "L7" to CommandEnum.L7,
            "L8" to CommandEnum.L8,
            "L9" to CommandEnum.L9,
            "R10" to CommandEnum.R10,
            "R1" to CommandEnum.R1,
            "R2" to CommandEnum.R2,
            "R3" to CommandEnum.R3,
            "R4" to CommandEnum.R4,
            "R5" to CommandEnum.R5,
            "R6" to CommandEnum.R6,
            "R7" to CommandEnum.R7,
            "R8" to CommandEnum.R8,
            "R9" to CommandEnum.R9,
            "GM" to CommandEnum.GM,
            "DN" to CommandEnum.DN,
            "STAT" to CommandEnum.STAT
        );


        private val CMD_RESP_MAP = mapOf<String, String>(
            "S1" to "S1A",
            "S2" to "S2A",
            "S3" to "S3A",
            "S4" to "S4A",
            "ASW1" to "ASW1A",
            "ASW0" to "ASW0A",
            "CE1" to "CE1A",
            "CE0" to "CE0A",
            "IR1" to "IR1A",
            "IR0" to "IR0A",
            "L10" to "L10A",
            "L1" to "L1A",
            "L2" to "L2A",
            "L3" to "L3A",
            "L4" to "L4A",
            "L5" to "L5A",
            "L6" to "L6A",
            "L7" to "L7A",
            "L8" to "L8A",
            "L9" to "L9A",
            "R10" to "L10A",
            "R1" to "L1A",
            "R2" to "L2A",
            "R3" to "L3A",
            "R4" to "L4A",
            "R5" to "L5A",
            "R6" to "L6A",
            "R7" to "L7A",
            "R8" to "L8A",
            "R9" to "L9A",
            "GM" to "GMA",
            "DN" to "DNA",
            "STAT" to "STAT"
        )


        var currentDevice: BluetoothDevice? = null
        var currentGatt: BluetoothGatt? = null
        var currentService: BluetoothGattService? = null


        private var onRespFunc: ((String) -> Unit)? = null
        //private var onNoRespFunc: (() -> Unit)? = null


        fun disconnect() {
            currentGatt?.also {
                currentGatt?.close()
                currentGatt?.disconnect()
            }
            currentGatt = null
        }

        fun isConnected(): Boolean {
            return currentGatt is BluetoothGatt && currentService is BluetoothGattService
        }

        fun getDeviceName(): String {
            return try {
                val dv = currentGatt!!.device
                if (dv != null) dv.name ?: dv.address else ""
            } catch (ex: kotlin.Exception) {
                LogConsole.writeBizLog(ex.localizedMessage, ex)
                dialog?.dismiss()
                activity.switch2BleScanPage()
                ""
            }
        }

        fun getDeviceAddress(): String {
            try {
                return if (currentDevice != null) currentDevice!!.address else ""
            } catch (ex: kotlin.Exception) {
                //LogConsole.writeBizLog(ex.localizedMessage, ex)
                Log.e("console", ex.localizedMessage, ex)
                dialog?.dismiss()
                activity.switch2BleScanPage()
                return ""
            }
        }

        var scanCallBack: ScanCallback? = null

        fun stopScan() {
            if (scanCallBack != null) {
                try {
                    BluetoothAdapter.getDefaultAdapter().bluetoothLeScanner.stopScan(scanCallBack)
                    scanCallBack = null
                } catch (ex: Exception) {
                    ToastUtils.showToastResLong(R.string.please_turn_on_bluetooth)
                }
            }
        }

        fun startScan(onFound: (ScanResult) -> Unit) {

            stopScan()

            val sf = ScanFilter.Builder().setServiceUuid(ParcelUuid(UUID.fromString(SERVICE_UUID))).build()
            val settings = ScanSettings.Builder().build()

            scanCallBack = object : ScanCallback() {
                override fun onScanResult(callbackType: Int, result: ScanResult) {
                    onFound(result)
                }

                override fun onBatchScanResults(results: MutableList<ScanResult>?) {
                    results?.also {
                        for (cur in results) {
                            onFound(cur)
                        }
                    }
                }
            }

            try {
                BluetoothAdapter.getDefaultAdapter().bluetoothLeScanner.startScan(
                    if (LIST_ALL_DEVICE) listOf() else listOf(sf), settings, scanCallBack
                )
            } catch (ex: Exception) {
                //LogConsole.writeBizLog("start scan fail!", ex)
                ToastUtils.showToastResLong(R.string.please_turn_on_bluetooth)
            }
        }

        fun clearService() {
            currentService = null
        }


        fun whenServicesDiscovered(
            gatt: BluetoothGatt?,
            status: Int,
            onSuccess: () -> Unit,
            onFail: ((Exception?) -> Unit)?
        ) {
            //LogConsole.writeBizLog("BLE services is discovered")
            currentService = gatt?.getService(UUID_SERVICE)

            if (currentService != null) {
                LogConsole.writeBizLog("discoverd service ${currentService?.uuid}")

                currentService?.characteristics?.forEach { curCh->
                    val w = (curCh.permissions and BluetoothGattCharacteristic.PERMISSION_WRITE)==BluetoothGattCharacteristic.PERMISSION_WRITE
                    val r = (curCh.permissions and BluetoothGattCharacteristic.PERMISSION_READ)==BluetoothGattCharacteristic.PERMISSION_READ
                    val pw = (curCh.properties and BluetoothGattCharacteristic.PROPERTY_WRITE)==BluetoothGattCharacteristic.PROPERTY_WRITE
                    val pr = (curCh.properties and BluetoothGattCharacteristic.PROPERTY_READ)==BluetoothGattCharacteristic.PROPERTY_READ
                    LogConsole.writeBizLog("-- char:${curCh.uuid} permission write:$w permission read:$r property write:$pw property read: $pr")

                    curCh.descriptors?.forEach { curDes->
                        val w = (curCh.permissions and BluetoothGattDescriptor.PERMISSION_WRITE)==BluetoothGattDescriptor.PERMISSION_WRITE
                        val r = (curCh.permissions and BluetoothGattDescriptor.PERMISSION_READ)==BluetoothGattDescriptor.PERMISSION_READ
                        LogConsole.writeBizLog("---- desc:${curDes.uuid} ${curDes.value} } permission write:$w permission read:$r")
                    }
                }

                val inChar = currentService?.getCharacteristic(UUID_INPUT)
                val outChar = currentService?.getCharacteristic(UUID_OUTPUT)


                enableNotifications(gatt!!, inChar!!)
                enableIndications(gatt, inChar)
                enableNotifications(gatt, outChar!!)
                enableIndications(gatt, outChar)


                TaskUtils.runInUiThread(onSuccess)
            } else {
                LogConsole.writeBizLog("BLE can't found service $UUID_SERVICE")
                dialog?.dismiss()
                alertMessage()
                ToastUtils.showToastResLong(R.string.not_found_service)
                TaskUtils.runInUiThread {
                    activity.switch2BleScanPage()
                }
            }
        }

        private val CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID =
            UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")

        fun enableNotifications(gatt:BluetoothGatt,   characteristic:BluetoothGattCharacteristic):Boolean {
            if (gatt == null || characteristic == null)
                return false

            // Check characteristic property
            val properties = characteristic.getProperties();
            if ((properties and BluetoothGattCharacteristic.PROPERTY_NOTIFY) == 0)
            return false

            Log.d("console", "gatt.setCharacteristicNotification(" + characteristic.getUuid() + ", true)");
            gatt.setCharacteristicNotification(characteristic, true);
            val descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID);
            if (descriptor != null) {
                descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                //Log.v("BLE", "Enabling notifications for " + characteristic.getUuid());
                //Log.d("BLE", "gatt.writeDescriptor(" + CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID + ", value=0x01-00)");
                return gatt.writeDescriptor(descriptor);
            }
            return false;
        }

        fun enableIndications(gatt:BluetoothGatt, characteristic: BluetoothGattCharacteristic):Boolean {
            /*
            if (gatt == null || characteristic == null)
                return false

            // Check characteristic property
            val properties = characteristic.getProperties();
            if ((properties and BluetoothGattCharacteristic.PROPERTY_INDICATE) == 0)
            return false

            Log.d("BLE", "gatt.setCharacteristicNotification(" + characteristic.getUuid() + ", true)")
            gatt.setCharacteristicNotification(characteristic, true);
            val descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID);
            if (descriptor != null) {
                descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
                //Log.v("BLE", "Enabling indications for " + characteristic.getUuid());
                //Log.d("BLE", "gatt.writeDescriptor(" + CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID + ", value=0x02-00)");
                return gatt.writeDescriptor(descriptor);
            }
            return false;
            */
            return true
        }

        fun whenCharacteristicWrite(
            gatt: BluetoothGatt?,
            characteristic: BluetoothGattCharacteristic?,
            status: Int
        ) {
            LogConsole.writeBizLog("recieve writen notify char:${characteristic?.uuid} value:${characteristic?.getStringValue(0)}")
            if (CommandCenter.isRunning()) {

                if (CommandCenter.isNoResponseCommand()) {
                //    LogConsole.writeBizLog("on write command:${CommandCenter.fetchCurrentCommandInstance()}  notify no response command continue")
                    onRespFunc?.also { func -> func("") }
                } else {
                    gatt?.also { g ->
                        if (g.connect()) {
                            g.getService(UUID_SERVICE)?.also { service ->
                                val inc = service.getCharacteristic(UUID_INPUT)
                                //currentGatt!!.close()
                                for(i in 0 .. 2){
                                    if(g.connect()) {
                                        val readRes = currentGatt!!.readCharacteristic(inc)
                                        LogConsole.writeBizLog("invoke read char:${inc.uuid} invoke res $readRes, and waiting for readed notify")
                                    }else{
                                        //LogConsole.writeBizLog("device was disconnected before read times $i")
                                        currentGatt!!.close()
                                    }
                                    break
                                }
                            }
                        } else {
                            LogConsole.writeBizLog("on write command:${CommandCenter.fetchCurrentCommandInstance()}  wrong, gatt is not connected")
                            if (CommandCenter.isRunning()) {
                                CommandCenter.notifyDeviceError()
                            }
                        }
                    }
                }
            }else{
                //LogConsole.writeBizLog("on write no running command!!!")
            }
        }

        fun whenCharacteristicRead(
            gatt: BluetoothGatt?,
            characteristic: BluetoothGattCharacteristic?,
            status: Int
        ) {
            val respString = characteristic?.getStringValue(0)
            LogConsole.writeBizLog("recieve readed notify char:${characteristic?.uuid} value:${respString}")
                if(CommandCenter.CURRENT_COMMAND!=null) {
                    /*
                    val respString: String? = if (HEX_MODE) {
                        String(Hex.decodeHex(characteristic?.getStringValue(0)), Charsets.ISO_8859_1)
                    } else {
                        characteristic?.getStringValue(0)

                    }*/
                    onRespFunc?.also { func -> func(respString ?: "") }
                }else{
                    LogConsole.writeBizLog("on read no command executing, resp string $respString")
                }

        }


        fun whenConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int, onFail: ((Exception?) -> Unit)?) {
            LogConsole.writeBizLog("on connection state change status:$status newState:$newState")
            if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
                if (currentService == null) {
                    if (currentGatt?.discoverServices() != true) {
                        TaskUtils.runInUiThread { onFail?.apply { this(null) } }
                    }
                }
            } else {
                //LogConsole.writeBizLog("on connection state change status:$status newState:$newState, that means not connected")
            }
        }


        /**
         * 连接设备.
         */
        fun connectDevice(device: BluetoothDevice, onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {

            //LogConsole.writeBizLog("connect device, name: ${device.name} address:${device.address}")

            stopScan()

            if (currentGatt != null) {
                currentGatt!!.close()
                currentGatt = null
            }

            val whenBund = {

                val cb = object : BluetoothGattCallback() {

                    override fun onCharacteristicWrite(
                        gatt: BluetoothGatt?,
                        characteristic: BluetoothGattCharacteristic?,
                        status: Int
                    ) {
                        whenCharacteristicWrite(gatt, characteristic, status)
                    }

                    override fun onCharacteristicRead(
                        gatt: BluetoothGatt?,
                        characteristic: BluetoothGattCharacteristic?,
                        status: Int
                    ) {
                        whenCharacteristicRead(gatt, characteristic, status)
                    }

                    override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
                        whenServicesDiscovered(gatt, status, onSuccess, onFail)
                    }

                    override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
                        whenConnectionStateChange(gatt, status, newState, onFail)
                    }
                }
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    PermissionUtils.whenHasAllPremissions(activity,
                        listOf(
                            Manifest.permission.ACCESS_COARSE_LOCATION,
                            Manifest.permission.ACCESS_FINE_LOCATION
                        ),
                        {
                            currentGatt =
                                    device.connectGatt(
                                        ApplicationUtils.APP,
                                        false,
                                        cb,
                                        BluetoothDevice.TRANSPORT_LE
                                    )
                        }) {}
                } else {
                    currentGatt = device.connectGatt(ApplicationUtils.APP, false, cb)
                }

            }

            if (device.bondState != BluetoothDevice.BOND_BONDED) {
                //LogConsole.writeBizLog("connect to device:${device.address} new bond")
                val filter = IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED)
                activity.registerReceiver(object : BroadcastReceiver() {
                    override fun onReceive(context: Context, intent: Intent) {

                        val state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1)
                        val pstate = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1)
                        //LogConsole.writeBizLog("connect to device:${device.address} on bond event, state:$state, pstate:$pstate")

                        val action = intent.action
                        // When discovery finds a device
                        val dev = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
                        if (BluetoothDevice.ACTION_BOND_STATE_CHANGED == action && state == BluetoothDevice.BOND_BONDED && device.address == dev.address) {
                            // onBtDisconnected()
                            TaskUtils.runInUiThread {
                                //LogConsole.writeBizLog("connect to device:${device.address} on bond event, bond success")
                                activity.unregisterReceiver(this)
                                whenBund()
                                dialog?.dismiss()
                            }
                        } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED == action && state == BluetoothDevice.BOND_NONE && pstate == BluetoothDevice.BOND_BONDING
                            && device.address == dev.address
                        ) {
                            //LogConsole.writeBizLog("connect to device:${device.address} on bond event, bond fail")
                            dialog?.dismiss()
                            alertUnbondMessage()
                            activity.switch2BleScanPage()
                        }
                    }
                }, filter)
                val createBondRes = device.createBond()
                LogConsole.i("create bond, and it's result is $createBondRes")
            } else {
                whenBund()
            }

        }


        fun sendCmdNoResp(cmd: String, onFinish: () -> Unit) {
            for (entry in CMD_TEXT_ENUM_MAP) {
                val key = entry.key
                if (cmd.startsWith(key, true)) {
                    val command = entry.value
                    CommandCenter.acceptCommand(command, cmd, { onFinish() }, {})
                    break
                }
            }

        }


        fun sendCmd(cmd: String, onResp: ((String) -> Unit)?): String {
            //LogConsole.writeBizLog("send command:$cmd")
            try {
                currentGatt?.connect()
                return currentGatt?.getService(UUID_SERVICE)?.let { service ->
                    try {
                        synchronized(this) {
                            val out = service.getCharacteristic(UUID_OUTPUT)
                            if (currentGatt != null) {

                                if (HEX_MODE) {
                                    out.value =
                                            Hex.encodeHexString(cmd.toByteArray(Charsets.ISO_8859_1)).toUpperCase()
                                                .toByteArray(Charsets.ISO_8859_1)
                                } else {
                                    out.value = cmd.toByteArray(Charsets.ISO_8859_1)
                                }

                                onRespFunc = onResp
                                val res = currentGatt!!.writeCharacteristic(out)
                                LogConsole.writeBizLog("sendCmd char:${out.uuid} write res:$res value:$cmd and waiting for writed notify")
                            } else {
                                LogConsole.writeBizLog("sendCmd gatt is null")
                            }
                            ""
                        }
                    } catch (ex: java.lang.Exception) {
                        LogConsole.writeBizLog("send command:$cmd writing exception", ex)
                        ""
                    }

                } ?: Any().run {
                    ""
                }
            } catch (ex: Exception) {
                LogConsole.writeBizLog("send command:$cmd connect exception", ex)
                throw RuntimeException(ex)
            }
        }

        @Suppress("unused")
        fun isResp(buf: StringBuffer): Boolean {
            var res = false
            for (res_key in CMD_RESP_MAP.values) {
                res = res || StringUtils.startsWith(buf, res_key)
                if (res) {
                    break
                }
            }
            if (buf.startsWith("STAT")) {
                res = buf.length == 13
            }
            return res
        }


        fun sendNormalCmd(cmd: String, onSuccess: (String) -> Unit, onFail: ((Exception?) -> Unit)?) {
            //LogConsole.writeBizLog("sending normal command:$cmd")
            for (entry in CMD_TEXT_ENUM_MAP) {
                val key = entry.key
                if (cmd.startsWith(key, true)) {
                    val command = entry.value
                    CommandCenter.acceptCommand(command, cmd, onSuccess, onFail)
                    break
                }
            }
        }

        @Suppress("unused")
        fun sendCmdS1(onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            sendNormalCmd("S1", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdS2(onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            sendNormalCmd("S2", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdS3(onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            sendNormalCmd("S3", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdS4(onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            sendNormalCmd("S4", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdASW0(onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            sendNormalCmd("ASW0", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdASW1(onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            sendNormalCmd("ASW1", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdCE0(onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            sendNormalCmd("CE0", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdCE1(onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            sendNormalCmd("CE1", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdIR0(onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            sendNormalCmd("IR0", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdIR1(onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            sendNormalCmd("IR1", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdL1(onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            sendNormalCmd("L1", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdL2(onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            sendNormalCmd("L2", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdL3(onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            sendNormalCmd("L3", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdL4(onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            sendNormalCmd("L4", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdL5(onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            sendNormalCmd("L5", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdL6(onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            sendNormalCmd("L6", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdL7(onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            sendNormalCmd("L7", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdL8(onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            sendNormalCmd("L8", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdL9(onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            sendNormalCmd("L9", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdL10(onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            sendNormalCmd("L10", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdR1(onSuccess: () -> Unit) {
            sendCmdNoResp("R1", onSuccess)
        }

        @Suppress("unused")
        fun sendCmdR2(onSuccess: () -> Unit) {
            sendCmdNoResp("R2", onSuccess)
        }

        @Suppress("unused")
        fun sendCmdR3(onSuccess: () -> Unit) {
            sendCmdNoResp("R3", onSuccess)
        }

        @Suppress("unused")
        fun sendCmdR4(onSuccess: () -> Unit) {
            sendCmdNoResp("R4", onSuccess)
        }

        @Suppress("unused")
        fun sendCmdR5(onSuccess: () -> Unit) {
            sendCmdNoResp("R5", onSuccess)
        }

        @Suppress("unused")
        fun sendCmdR6(onSuccess: () -> Unit) {
            sendCmdNoResp("R6", onSuccess)
        }

        @Suppress("unused")
        fun sendCmdR7(onSuccess: () -> Unit) {
            sendCmdNoResp("R7", onSuccess)
        }

        @Suppress("unused")
        fun sendCmdR8(onSuccess: () -> Unit) {
            sendCmdNoResp("R8", onSuccess)
        }

        @Suppress("unused")
        fun sendCmdR9(onSuccess: () -> Unit) {
            sendCmdNoResp("R9", onSuccess)
        }

        @Suppress("unused")
        fun sendCmdR10(onSuccess: () -> Unit) {
            sendCmdNoResp("R10", onSuccess)
        }

        @Suppress("unused")
        fun sendCmdGreatingMessage(greetingMessage: String, onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            CommandCenter.acceptCommand(CommandEnum.GM, "GM$greetingMessage\r\n", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdDeviceName(deviceName: String, onSuccess: () -> Unit, onFail: ((Exception?) -> Unit)?) {
            CommandCenter.acceptCommand(CommandEnum.DN, "DN$deviceName\r\n", { onSuccess() }, onFail)
        }

        @Suppress("unused")
        fun sendCmdSTAT(onSuccess: (String) -> Unit, onFail: ((Exception?) -> Unit)?) {
            CommandCenter.acceptCommand(
                CommandEnum.STAT,
                CommandEnum.STAT.name,
                { stat -> onSuccess(stat) },
                onFail
            )
        }

        @Suppress("unused")
        fun getStatVersion(stat: String): String {
            return stat.substring(0, 1)
        }

        @Suppress("unused")
        fun getStatModule(stat: String): String {
            return stat.substring(1, 4)
        }


        fun getStatHdmi(stat: String): String {
            return stat.substring(4, 5)
        }

        fun getStatAutoSwitch(stat: String): String {
            Log.d("console","stat..."+stat.substring(5, 6))
            return stat.substring(5, 6)

        }

        fun getStatCec(stat: String): String {
            return stat.substring(6, 7)
        }

        fun getStatIr(stat: String): String {
            return stat.substring(7, 8)
        }

        fun getStatLean(stat: String): String {
            return stat.substring(8, 9)
        }

        fun isOn(status: String): Boolean {
            return status == "1"
        }

        fun isAutoSwitchOn(stat: String): Boolean {
            return isOn(getStatAutoSwitch(stat))
        }

        fun isCecOn(stat: String): Boolean {
            return isOn(getStatCec(stat))
        }

        fun isIrOn(stat: String): Boolean {
            return isOn(getStatIr(stat))
        }

        fun isLeanOn(stat: String): Boolean {
            return isOn(getStatLean(stat))
        }

        @Suppress("DEPRECATION")
        fun alertMessage() {
            val dialog =
                android.support.v7.app.AlertDialog.Builder(Objects.requireNonNull<FragmentActivity>(activity))
                    .setTitle(activity.getString(R.string.not_found_service_alert_title))
                    .setIcon(R.drawable.logo)
                    .setMessage(activity.getString(R.string.not_found_service_alert_message))
                    .setPositiveButton(activity.getString(R.string.not_found_service_alert_ok_button_text), null)
                    //.setNegativeButton("cancle", null)
                    .show()
            dialog.getButton(android.support.v7.app.AlertDialog.BUTTON_POSITIVE)
                .setTextColor(activity.resources.getColor(R.color.button_negative))
        }

        @Suppress("DEPRECATION")
        fun alertUnbondMessage() {

            val dialog =
                android.support.v7.app.AlertDialog.Builder(Objects.requireNonNull<FragmentActivity>(activity))
                    .setTitle(activity.getString(R.string.can_not_bound_dev_title))
                    .setIcon(R.drawable.logo)
                    .setMessage(activity.getString(R.string.can_not_bound_dev_msg))
                    .setPositiveButton(activity.getString(R.string.can_not_bound_dev_ok_button_text), null)
                    //.setNegativeButton("cancle", null)
                    .show()
            dialog.getButton(android.support.v7.app.AlertDialog.BUTTON_POSITIVE)
                .setTextColor(activity.resources.getColor(R.color.button_negative))
        }
    }
}


